#pragma once
#include <media/videobuf2-vmalloc.h>
#include <linux/timekeeping.h>

int webcamTryFormat( struct driverInstance*, struct v4l2_pix_format*, char setFlag );
struct webcam_control* usbcam_ctrl_find( struct driverInstance*, u32 );
int webcamCaptureStart( struct driverInstance* );

int webcamInit( struct driverInstance*, const struct usb_device_id* );
void webcamRelease( struct driverInstance* );


/****************************
*         Videobuf2         *
****************************/

static int queue_setup_callback( struct vb2_queue* videobufQueue, unsigned int* numBuffers, unsigned int* numPlanes, unsigned int sizes[], struct device* alloc_ctxs[] );
static int buf_prepare_callback( struct vb2_buffer* videoBuffer );
static void buf_queue_callback( struct vb2_buffer* videoBuffer );
static int start_streaming_callback( struct vb2_queue* videobufQueue, unsigned int count );
static void stop_streaming_callback( struct vb2_queue* videobufQueue );


//Note that since videobuf2Queue->lock is set we can use the standard vb2_ops_wait_prepare/finish helper functions. 
//If videobuf2Queue->lock would be NULL, then this driver would have to provide these ops.
static const struct vb2_ops videobuf2QueueOps = {
	
	.queue_setup     = queue_setup_callback,
	.buf_prepare     = buf_prepare_callback,
	.buf_queue       = buf_queue_callback,
	.start_streaming = start_streaming_callback,
	.stop_streaming  = stop_streaming_callback,
	.wait_prepare    = vb2_ops_wait_prepare,
	.wait_finish     = vb2_ops_wait_finish,
};


//The set of file operations. Note that all these ops are standard core helper functions.
static const struct v4l2_file_operations v4l2FileOperations = {
	
	.owner          = THIS_MODULE,
	.open           = v4l2_fh_open,
	.release        = vb2_fop_release,
	.unlocked_ioctl = video_ioctl2,
	.read           = vb2_fop_read,
	.mmap           = vb2_fop_mmap,
	.poll           = vb2_fop_poll,
};

/****************************
*   videoDevice ioctl ops   *
****************************/

static int vidioc_querycap_callback( struct file* file, void* fh, struct v4l2_capability* cap );

static int vidioc_enum_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_fmtdesc* f );
static int vidioc_g_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f );
static int vidioc_s_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f );
static int vidioc_try_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f );

static int vidioc_enum_input_callback( struct file* file, void* fh, struct v4l2_input* inp );
static int vidioc_g_input_callback( struct file* file, void* fh, unsigned int* i );
static int vidioc_s_input_callback( struct file* file, void* fh, unsigned int i );

static int vidioc_querystd_callback( struct file* file, void* fh, v4l2_std_id* argp );
static int vidioc_g_std_callback( struct file* file, void* fh, v4l2_std_id* argp );
static int vidioc_s_std_callback( struct file* file, void* fh, v4l2_std_id argp );

static int vidioc_enum_framesizes_callback( struct file* file, void* fh, struct v4l2_frmsizeenum* fsize );
static int vidioc_enum_frameintervals_callback( struct file* file, void* fh, struct v4l2_frmivalenum* fival );

//full list in include/media/v4l2-ioctl.h
static const struct v4l2_ioctl_ops videoDeviceIoctlOps = {
	
	.vidioc_querycap            = vidioc_querycap_callback,
	
	.vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap_callback,
	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap_callback,
	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap_callback,
	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap_callback,
	
	.vidioc_enum_input          = vidioc_enum_input_callback,
	.vidioc_g_input             = vidioc_g_input_callback,
	.vidioc_s_input             = vidioc_s_input_callback,
	
	.vidioc_querystd            = vidioc_querystd_callback,
	.vidioc_g_std               = vidioc_g_std_callback,
	.vidioc_s_std               = vidioc_s_std_callback,
	
	.vidioc_enum_framesizes     = vidioc_enum_framesizes_callback,
	.vidioc_enum_frameintervals = vidioc_enum_frameintervals_callback,
	
	//standart helpers
	.vidioc_reqbufs     = vb2_ioctl_reqbufs,
	.vidioc_create_bufs = vb2_ioctl_create_bufs,
	.vidioc_querybuf    = vb2_ioctl_querybuf,
	.vidioc_qbuf        = vb2_ioctl_qbuf,
	.vidioc_dqbuf       = vb2_ioctl_dqbuf,
	.vidioc_expbuf      = vb2_ioctl_expbuf,
	
	.vidioc_streamon    = vb2_ioctl_streamon,
	.vidioc_streamoff   = vb2_ioctl_streamoff,
	
};

/****************************
*           USB             *
****************************/



#define R5U870_DEVICE_UVC(VID, PID, DINFO) \
	.match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, \
	.idVendor           = (VID),           \
	.idProduct          = (PID),           \
	.bInterfaceClass    = USB_CLASS_VIDEO, \
	.bInterfaceSubClass = 1,               \
	.bInterfaceProtocol = 0,               \
	.driver_info        = (DINFO)

static const struct usb_device_id id_table[] = {
	{ USB_DEVICE(0x05CA, 0x1830), .driver_info = R5U870_DI_VGP_VCC2_SZ },
	{ USB_DEVICE(0x05CA, 0x1832), .driver_info = R5U870_DI_VGP_VCC3 },
	{ USB_DEVICE(0x05CA, 0x1833), .driver_info = R5U870_DI_VGP_VCC2_AR1 },
	{ USB_DEVICE(0x05CA, 0x1834), .driver_info = R5U870_DI_VGP_VCC2_AR2 },
	{ USB_DEVICE(0x05CA, 0x1870), .driver_info = R5U870_DI_HP_PAVWC_WDM },

	{ R5U870_DEVICE_UVC(0x05CA, 0x1810, R5U870_DI_HP_PAVWC_UVC) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x1812, R5U870_DI_HP_PAVWC_UVC_NOFW) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x1835, R5U870_DI_VGP_VCC5) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x1836, R5U870_DI_VGP_VCC4) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x1837, R5U870_DI_VGP_VCC4_VFLIP) },
	/* 0x1838 does not appear to have ever been released */
	{ R5U870_DEVICE_UVC(0x05CA, 0x1839, R5U870_DI_VGP_VCC6) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x183a, R5U870_DI_VGP_VCC7) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x183b, R5U870_DI_VGP_VCC8) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x183e, R5U870_DI_VGP_VCC9) },
	{ R5U870_DEVICE_UVC(0x05CA, 0x1841, R5U870_DI_FUJITSU) },
	{ },
};


static int usbDeviceProbe_callback( struct usb_interface* usbInterface, const struct usb_device_id* usbDeviceId );
static void usbDeviceDisconnect_callback( struct usb_interface* usbInterface );

static struct usb_driver usbDriver_s = {
	.name = KBUILD_MODNAME,
	.id_table = id_table,
	.probe = usbDeviceProbe_callback,
	.disconnect = usbDeviceDisconnect_callback,
};










































































